//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

import React, { useEffect, useState } from "react";
import { observer } from 'mobx-react';
import { Button, Card, message, Modal, Table, Form, Input, Select, List, Space, Popover } from "antd";
import type { ServerInfo } from "@/api/project_server";
import {
    list_server as list_project_server, add_server as add_project_server, update_server as update_project_server, remove_server as remove_project_server,
    SERVER_TYPE_GRPC, SERVER_TYPE_MONGO, SERVER_TYPE_MYSQL, SERVER_TYPE_POSTGRES, SERVER_TYPE_REDIS, SERVER_TYPE_SSH
} from "@/api/project_server";
import { useStores } from "@/hooks";
import type { UserServerInfo, SshServerInfo, SqlServerInfo, MongoServerInfo, RedisServerInfo, GrpcServerInfo } from "@/api/user_server";
import { list_server as list_user_server, add_server as add_user_server, update_server as update_user_server } from "@/api/user_server";
import { request } from "@/utils/request";
import { APP_TYPE_GRPC, APP_TYPE_MONGO, APP_TYPE_MYSQL, APP_TYPE_POSTGRES, APP_TYPE_REDIS, APP_TYPE_SSH, APP_TYPE_UNKWOWN, list_app_by_type, type APP_TYPE } from "@/api/appstore";
import type { ColumnsType } from 'antd/lib/table';
import { uniqId } from "@/utils/utils";
import { MinusCircleOutlined, MoreOutlined, PlusCircleOutlined } from "@ant-design/icons";
import { get_global_server_addr } from "@/api/client_cfg";
import EditServModal from "@/pages/Workbench/components/userserv/EditServModal";

interface EditProjectServerModalProps {
    serverInfo?: ServerInfo;
    onCancel: () => void;
    onOk: () => void;
}

interface AddrWithId {
    id: string;
    addr: string;
}

const EditProjectServerModal = observer((props: EditProjectServerModalProps) => {
    const userStore = useStores('userStore');
    const projectStore = useStores('projectStore');

    const [serverName, setServerName] = useState(props.serverInfo?.basic_info.server_name ?? "");
    const [serverType, setServerType] = useState(props.serverInfo?.basic_info.server_type ?? SERVER_TYPE_SSH);
    const [addrList, setAddrList] = useState<AddrWithId[]>((props.serverInfo?.basic_info.addr_list ?? [""]).map(addr => ({
        id: uniqId(),
        addr: addr,
    })));
    const [hasChange, setHasChange] = useState(false);

    const addServer = async () => {
        await request(add_project_server({
            session_id: userStore.sessionId,
            project_id: projectStore.curProjectId,
            basic_info: {
                server_name: serverName,
                server_type: serverType,
                addr_list: addrList.map(item => item.addr),
            },
        }));
        message.info("增加成功");
        props.onOk();
    };

    const updateServer = async () => {
        if (props.serverInfo == undefined) {
            return;
        }
        await request(update_project_server({
            session_id: userStore.sessionId,
            project_id: projectStore.curProjectId,
            server_id: props.serverInfo.server_id,
            basic_info: {
                server_name: serverName,
                server_type: props.serverInfo.basic_info.server_type,
                addr_list: addrList.map(item => item.addr),
            },
        }));
        message.info("修改成功");
        props.onOk();
    };

    const checkValid = () => {
        if (!hasChange) {
            return false;
        }
        if (serverName == "") {
            return false;
        }
        if (addrList.length == 0) {
            return false;
        }
        for (const addr of addrList) {
            if (addr.addr.trim() == "") {
                return false;
            }
        }
        return true;
    };

    return (
        <Modal open title={`${props.serverInfo == undefined ? "增加" : "修改"}服务器`} mask={false}
            okText={props.serverInfo == undefined ? "增加" : "修改"} okButtonProps={{ disabled: !checkValid() }}
            onCancel={e => {
                e.stopPropagation();
                e.preventDefault();
                props.onCancel();
            }}
            onOk={e => {
                e.stopPropagation();
                e.preventDefault();
                if (props.serverInfo == undefined) {
                    addServer();
                } else {
                    updateServer();
                }
            }}>
            <Form labelCol={{ span: 3 }}>
                <Form.Item label="服务名称">
                    <Input value={serverName} onChange={e => {
                        e.stopPropagation();
                        e.preventDefault();
                        setServerName(e.target.value.trim());
                        setHasChange(true);
                    }} />
                </Form.Item>
                <Form.Item label="类型">
                    <Select value={serverType} onChange={value => setServerType(value)} disabled={props.serverInfo != undefined}>
                        <Select.Option value={SERVER_TYPE_SSH}>SSH</Select.Option>
                        <Select.Option value={SERVER_TYPE_MYSQL}>MYSQL</Select.Option>
                        <Select.Option value={SERVER_TYPE_POSTGRES}>POSTGRES</Select.Option>
                        <Select.Option value={SERVER_TYPE_MONGO}>MONGO</Select.Option>
                        <Select.Option value={SERVER_TYPE_REDIS}>REDIS</Select.Option>
                        <Select.Option value={SERVER_TYPE_GRPC}>GRPC</Select.Option>
                    </Select>
                </Form.Item>
                <Form.Item label="服务地址">
                    <List rowKey="id" dataSource={addrList} pagination={false} renderItem={(addrItem, itemIndex) => (
                        <List.Item extra={
                            <>
                                {[SERVER_TYPE_MONGO, SERVER_TYPE_REDIS].includes(serverType) && (
                                    <Space>
                                        <Button type="link" icon={<PlusCircleOutlined />} style={{ minWidth: 0, padding: "0px 0px" }}
                                            onClick={e => {
                                                e.stopPropagation();
                                                e.preventDefault();
                                                const tmpList = addrList.slice();
                                                tmpList.splice(itemIndex + 1, 0, {
                                                    id: uniqId(),
                                                    addr: "",
                                                });
                                                setAddrList(tmpList);
                                            }} />
                                        <Button type="link" icon={<MinusCircleOutlined />} style={{ minWidth: 0, padding: "0px 0px" }} disabled={itemIndex == 0}
                                            onClick={e => {
                                                e.stopPropagation();
                                                e.preventDefault();
                                                const tmpList = addrList.filter(item => item.id != addrItem.id);
                                                setAddrList(tmpList);
                                            }} />
                                    </Space>
                                )}
                            </>
                        }>
                            <Input value={addrItem.addr} onChange={e => {
                                e.stopPropagation();
                                e.preventDefault();
                                const tmpList = addrList.slice();
                                tmpList[itemIndex].addr = e.target.value.trim();
                                setAddrList(tmpList);
                                setHasChange(true);
                            }} />
                        </List.Item>
                    )} />
                </Form.Item>
            </Form>
        </Modal>
    );
});

const ServerList = () => {
    const userStore = useStores('userStore');
    const projectStore = useStores('projectStore');
    const appStore = useStores("appStore");


    const [showAddModal, setShowAddModal] = useState(false);
    const [serverList, setServerList] = useState<ServerInfo[]>([]);
    const [editAuthServerInfo, setEditAuthServerInfo] = useState<UserServerInfo | null>(null);
    const [updateServerInfo, setUpdateServerInfo] = useState<ServerInfo | null>(null);
    const [removeServerInfo, setRemoveServerInfo] = useState<ServerInfo | null>(null);

    const addUserServer = async (prjServerInfo: ServerInfo) => {
        let appType: APP_TYPE = APP_TYPE_UNKWOWN;
        let serverInfo = "";
        if (prjServerInfo.basic_info.server_type == SERVER_TYPE_SSH) {
            appType = APP_TYPE_SSH;
            const tmpInfo: SshServerInfo = {
                addr: prjServerInfo.basic_info.addr_list.at(0) ?? "",
                username: "",
                usePrivKey: false,
                password: "",
                privKeyPath: "",
                privKeyPassword: "",
            };
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_MYSQL) {
            appType = APP_TYPE_MYSQL;
            const tmpInfo: SqlServerInfo = {
                driver: "mysql",
                addr: prjServerInfo.basic_info.addr_list.at(0) ?? "",
                username: "",
                password: "",
            };
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_POSTGRES) {
            appType = APP_TYPE_POSTGRES;
            const tmpInfo: SqlServerInfo = {
                driver: "postgres",
                addr: prjServerInfo.basic_info.addr_list.at(0) ?? "",
                username: "",
                password: "",
            };
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_MONGO) {
            appType = APP_TYPE_MONGO;
            const tmpInfo: MongoServerInfo = {
                addrs: prjServerInfo.basic_info.addr_list,
                username: "",
                password: "",
                authSource: "admin",
                authMechanism: "SCRAM-SHA-256",
                replicaSet: "",
                defaultDb: "",
            };
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_REDIS) {
            appType = APP_TYPE_REDIS;
            const tmpInfo: RedisServerInfo = {
                addrs: prjServerInfo.basic_info.addr_list,
                dbId: 0,
                username: "",
                password: "",
            };
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_GRPC) {
            appType = APP_TYPE_GRPC;
            const tmpInfo: GrpcServerInfo = {
                addr: prjServerInfo.basic_info.addr_list.at(0) ?? "",
                rootPath: "",
                importPathList: [],
                secure: false,
            };
            serverInfo = JSON.stringify(tmpInfo);
        }
        if (appType == APP_TYPE_UNKWOWN || serverInfo == "") {
            return;
        }
        await add_user_server({
            id: prjServerInfo.server_id,
            name: prjServerInfo.basic_info.server_name,
            server_type: appType,
            server_info: serverInfo,
            project_id: projectStore.curProjectId,
        });
    };

    const updateUserServer = async (prjServerInfo: ServerInfo, userSerInfo: UserServerInfo) => {
        let appType: APP_TYPE = APP_TYPE_UNKWOWN;
        let serverInfo = "";

        if (prjServerInfo.basic_info.server_type == SERVER_TYPE_SSH) {
            appType = APP_TYPE_SSH;
            const tmpInfo = JSON.parse(userSerInfo.server_info) as SshServerInfo;
            if (prjServerInfo.basic_info.server_name == userSerInfo.name && tmpInfo.addr == prjServerInfo.basic_info.addr_list.at(0) && userSerInfo.project_id == projectStore.curProjectId) {
                return;
            }
            tmpInfo.addr = prjServerInfo.basic_info.addr_list.at(0) ?? "";
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_MYSQL) {
            appType = APP_TYPE_MYSQL;
            const tmpInfo = JSON.parse(userSerInfo.server_info) as SqlServerInfo;
            if (prjServerInfo.basic_info.server_name == userSerInfo.name && tmpInfo.addr == prjServerInfo.basic_info.addr_list.at(0) && userSerInfo.project_id == projectStore.curProjectId) {
                return;
            }
            tmpInfo.addr = prjServerInfo.basic_info.addr_list.at(0) ?? "";
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_POSTGRES) {
            appType = APP_TYPE_POSTGRES;
            const tmpInfo = JSON.parse(userSerInfo.server_info) as SqlServerInfo;
            if (prjServerInfo.basic_info.server_name == userSerInfo.name && tmpInfo.addr == prjServerInfo.basic_info.addr_list.at(0) && userSerInfo.project_id == projectStore.curProjectId) {
                return;
            }
            tmpInfo.addr = prjServerInfo.basic_info.addr_list.at(0) ?? "";
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_MONGO) {
            appType = APP_TYPE_MONGO;
            const tmpInfo = JSON.parse(userSerInfo.server_info) as MongoServerInfo;
            if (prjServerInfo.basic_info.server_name == userSerInfo.name && tmpInfo.addrs.join(",") == prjServerInfo.basic_info.addr_list.join(",") && userSerInfo.project_id == projectStore.curProjectId) {
                return;
            }
            tmpInfo.addrs = prjServerInfo.basic_info.addr_list;
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_REDIS) {
            appType = APP_TYPE_REDIS;
            const tmpInfo = JSON.parse(userSerInfo.server_info) as RedisServerInfo;
            if (prjServerInfo.basic_info.server_name == userSerInfo.name && tmpInfo.addrs.join(",") == prjServerInfo.basic_info.addr_list.join(",") && userSerInfo.project_id == projectStore.curProjectId) {
                return;
            }
            tmpInfo.addrs = prjServerInfo.basic_info.addr_list;
            serverInfo = JSON.stringify(tmpInfo);
        } else if (prjServerInfo.basic_info.server_type == SERVER_TYPE_GRPC) {
            appType = APP_TYPE_GRPC;
            const tmpInfo = JSON.parse(userSerInfo.server_info) as GrpcServerInfo;
            if (prjServerInfo.basic_info.server_name == userSerInfo.name && tmpInfo.addr == prjServerInfo.basic_info.addr_list.at(0)) {
                return;
            }
            tmpInfo.addr = prjServerInfo.basic_info.addr_list.at(0) ?? "";
            serverInfo = JSON.stringify(tmpInfo);
        }
        if (appType == APP_TYPE_UNKWOWN || serverInfo == "") {
            return;
        }
        await update_user_server({
            id: prjServerInfo.server_id,
            name: prjServerInfo.basic_info.server_name,
            server_type: appType,
            server_info: serverInfo,
            project_id: projectStore.curProjectId,
        });
    };

    const loadServerList = async () => {
        //加载我的服务列表
        const userServerList = await list_user_server();
        const userServerIdList = userServerList.map(item => item.id);
        //加载服务器列表
        const res = await request(list_project_server({
            session_id: userStore.sessionId,
            project_id: projectStore.curProjectId,
        }));
        //增加缺失服务
        for (const prjServerInfo of res.server_info_list) {
            if (userServerIdList.includes(prjServerInfo.server_id)) {
                const userServerInfo = userServerList.find(item => item.id == prjServerInfo.server_id);
                if (userServerInfo != undefined) {
                    updateUserServer(prjServerInfo, userServerInfo)
                }
            } else {
                await addUserServer(prjServerInfo);
            }
        }
        setServerList(res.server_info_list);
    };

    const openApp = async (serverId: string) => {
        const userServerList = await list_user_server();
        const userServer = userServerList.find(item => item.id == serverId);
        if (userServer == undefined) {
            message.error("未找到相关应用");
            return;
        }

        const addr = await get_global_server_addr();
        const res = await list_app_by_type(addr, {
            app_type: userServer.server_type,
            session_id: userStore.sessionId,
        });
        if (res.app_info_list.length == 0) {
            message.warn("没有匹配微应用")
        } else {
            appStore.openMinAppParam = {
                minAppId: res.app_info_list[0].app_id,
                extraInfo: JSON.stringify(userServer.server_info),
                extraInfoName: JSON.stringify(userServer.name),
            };
        }
    };

    const findEditAuthServer = async (serverId: string) => {
        const userServerList = await list_user_server();
        const userServer = userServerList.find(item => item.id == serverId);
        if (userServer == undefined) {
            message.error("未找到相关配置");
            return;
        }
        userServer.project_id = projectStore.curProjectId;
        setEditAuthServerInfo(userServer);
    };

    const removeServer = async () => {
        if (removeServerInfo == null) {
            return;
        }
        await request(remove_project_server({
            session_id: userStore.sessionId,
            project_id: projectStore.curProjectId,
            server_id: removeServerInfo.server_id,
        }));
        message.info("删除成功");
        setRemoveServerInfo(null);
        await loadServerList();
    };

    const columns: ColumnsType<ServerInfo> = [
        {
            title: "名称",
            dataIndex: ["basic_info", "server_name"],
            width: 100,
        },
        {
            title: "类型",
            width: 80,
            render: (_, row: ServerInfo) => {
                if (row.basic_info.server_type == SERVER_TYPE_SSH) {
                    return "SSH";
                } else if (row.basic_info.server_type == SERVER_TYPE_MYSQL) {
                    return "MYSQL";
                } else if (row.basic_info.server_type == SERVER_TYPE_POSTGRES) {
                    return "POSTGRES";
                } else if (row.basic_info.server_type == SERVER_TYPE_MONGO) {
                    return "MONGO";
                } else if (row.basic_info.server_type == SERVER_TYPE_REDIS) {
                    return "REDIS";
                } else if (row.basic_info.server_type == SERVER_TYPE_GRPC) {
                    return "GRPC";
                }
                return "";
            },
        },
        {
            title: "服务地址",
            render: (_, row: ServerInfo) => row.basic_info.addr_list.join(","),
        },
        {
            title: "操作",
            render: (_, row: ServerInfo) => (
                <Space>
                    <Button type="primary" onClick={e => {
                        e.stopPropagation();
                        e.preventDefault();
                        openApp(row.server_id);
                    }}>访问服务</Button>
                    <Button type="link" style={{ minWidth: 0, padding: "0px 0px" }} onClick={e => {
                        e.stopPropagation();
                        e.preventDefault();
                        findEditAuthServer(row.server_id);
                    }}>验证信息</Button>
                    {projectStore.isAdmin && (
                        <Popover trigger="click" placement="bottom" content={
                            <Space direction="vertical">
                                <Button type="link" onClick={e => {
                                    e.stopPropagation();
                                    e.preventDefault();
                                    setUpdateServerInfo(row);
                                }}>修改</Button>
                                <Button type="link" danger onClick={e => {
                                    e.stopPropagation();
                                    e.preventDefault();
                                    setRemoveServerInfo(row);
                                }}>删除</Button>
                            </Space>
                        }>
                            <MoreOutlined />
                        </Popover>
                    )}
                </Space>
            ),
        }
    ];

    useEffect(() => {
        if (projectStore.curProjectId != "") {
            loadServerList();
        }
    }, [projectStore.curProjectId]);


    return (
        <Card title="服务列表"
            headStyle={{ backgroundColor: "#eee", fontSize: "16px", fontWeight: 600 }} style={{ marginBottom: "10px" }}
            extra={
                <>
                    {projectStore.isAdmin && (
                        <Button type="primary" onClick={e => {
                            e.stopPropagation();
                            e.preventDefault();
                            setShowAddModal(true);
                        }}>
                            增加
                        </Button>
                    )}
                </>
            }>
            <Table rowKey="server_id" dataSource={serverList} columns={columns} pagination={false} scroll={{ y: "500px" }} />
            {showAddModal == true && (
                <EditProjectServerModal onCancel={() => setShowAddModal(false)} onOk={() => {
                    setShowAddModal(false);
                    loadServerList();
                }} />
            )}
            {editAuthServerInfo != null && (
                <EditServModal serverInfo={editAuthServerInfo} appType={editAuthServerInfo.server_type}
                    onCancel={() => setEditAuthServerInfo(null)} onOk={() => setEditAuthServerInfo(null)} />
            )}
            {updateServerInfo != null && (
                <EditProjectServerModal serverInfo={updateServerInfo}
                    onCancel={() => setUpdateServerInfo(null)}
                    onOk={() => {
                        setUpdateServerInfo(null);
                        loadServerList();
                    }} />
            )}
            {removeServerInfo != null && (
                <Modal open title="删除服务" mask={false}
                    okText="删除" okButtonProps={{ danger: true }}
                    onCancel={e => {
                        e.stopPropagation();
                        e.preventDefault();
                        setRemoveServerInfo(null);
                    }}
                    onOk={e => {
                        e.stopPropagation();
                        e.preventDefault();
                        removeServer();
                    }}>
                    是否删除服务&nbsp;{removeServerInfo.basic_info.server_name}&nbsp;?
                </Modal>
            )}
        </Card>
    );
};

export default observer(ServerList);